package com.k8.registry;

import com.k8.common.event.Event;
import com.k8.common.event.SynListener;
import com.k8.rpc.Protocol;
import com.k8.rpc.expoter.Exporter;
import com.k8.rpc.url.URL;
import com.k8.rpc.util.URLUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static com.k8.common.constants.CommonKeyConstants.EXPORTER_KEY;
import static com.k8.common.constants.CommonKeyConstants.RpcKeyConstant.EXPORTER_SIGNATURE_KEY;

/**
 * 向本地缓存文件中添加properties格式的服务缓存，默认应当
 */
@Slf4j
public class NotifyListener2 implements SynListener {
    private Exporter<?> exporter;
    private URL registerUrl;

    private String signature;
    private Protocol protocol;
    private volatile boolean canDisposal = true;
    private Lock lock = new ReentrantLock(false);

    public NotifyListener2(Exporter<?> exporter, URL registryUrl, String signature, Protocol adaptiveProtocol) {
        this.exporter = exporter;
        this.registerUrl = URLUtils.copy(registryUrl);
        this.signature = signature;
        this.protocol = adaptiveProtocol;
    }

    @Override
    public boolean judgeEventType(Event event) {
        if (event instanceof NotifyEvent) return true;
        return false;
    }

    @Override
    public boolean canDispose(Event event) {
        if (!canDisposal) return false;
        if (event instanceof NotifyEvent notifyEvent) {
            URL url = notifyEvent.getValue();
            Object sig = url.getAttribute(EXPORTER_SIGNATURE_KEY);
            if (sig == null || !(sig instanceof String)) {
                log.warn("Error notify listener , sig is :" + sig.toString());
                return false;
            }
            String exporterSignature = (String) sig;
            if (exporterSignature.equals(signature)) return true;
            return false;
        }
        return false;
    }

    /**
     * 重新导出服务的入口程序
     * 在dubbo中reExport由RegistryProtocol执行
     * 根据新的注册中心修改的配置判断修改的配置是否是需要重启才能生效的
     * 如果是则重启，并且会生成新的exporter
     * 由于我们的exporter并没有使用一个容器去保存，只通过invocationTemplate倒排索引进行映射
     * 所以重启服务时不再创建新的exporter，而是先将exporter设置为不可用，等重启服务后再将其设置为可用
     * <p>
     * 实现synListener原因：
     * 1.避免url的修改的线程并发导致不安全
     * 2.避免同时多个线程在重启服务
     */
    @Override
    public void disposal(Event event) {
        if (!canDisposal) return;
        event = event;
        URL url = ((NotifyEvent) event).getValue();
        Map<String, String> urlParams = url.getUrlParams();
        boolean change = false;
        Set<String> keyS = urlParams.keySet();
        URL protocolURL = (URL) registerUrl.getAttribute(EXPORTER_KEY);
        if (protocolURL == null) {
            log.warn("URL to exporter is not put in registerUrl");
            //此时别的事件进行处理同样无法处理，所以直接将该字段值改为false标记无法执行
            canDisposal = false;
            return;
        }
        for (String key : keyS) {
            String oldValue = protocolURL.getParameter(key);
            String value = urlParams.get(key);
            if (!value.equals(oldValue)) {
                protocolURL.setParameter(key, value);
                change = true;
            }

        }
        if (change) {

        }
    }

    @Override
    public Lock getLock() {
        return this.lock;
    }

    public static class NotifyEvent implements Event {
        private URL value;
        private Throwable exception;

        public NotifyEvent(URL url) {
            this.value = url;
        }

        @Override
        public Throwable getException() {
            return null;
        }

        public void setException(Throwable exception) {
            this.exception = exception;
        }

        @Override
        public URL getValue() {
            return this.value;
        }
    }
}
